package cn.schoolwow.quickflow.service.flowContext.execute;

import cn.schoolwow.quickflow.QuickFlowExecutor;
import cn.schoolwow.quickflow.domain.FlowContext;
import cn.schoolwow.quickflow.domain.FlowExecutorConfig;
import cn.schoolwow.quickflow.exception.BrokenCurrentCompositeBusinessException;
import cn.schoolwow.quickflow.exception.BrokenCurrentFlowException;
import cn.schoolwow.quickflow.exception.BrokenException;
import cn.schoolwow.quickflow.exception.QuickFlowRuntimeException;
import cn.schoolwow.quickflow.flow.BusinessFlow;
import cn.schoolwow.quickflow.flow.CompositeBusinessFlow;
import cn.schoolwow.quickflow.flow.FunctionFlow;
import cn.schoolwow.quickflow.util.QuickFlowUtil;

import java.util.HashMap;
import java.util.Map;

public class FlowContextExecuteOperationImpl implements FlowContextExecuteOperation {
    private FlowExecutorConfig flowExecutorConfig;

    public FlowContextExecuteOperationImpl(FlowExecutorConfig flowExecutorConfig) {
        this.flowExecutorConfig = flowExecutorConfig;
    }

    @Override
    public void brokenCurrentFlow(String reason) {
        throw new BrokenCurrentFlowException(reason);
    }

    @Override
    public void brokenCurrentCompositeBusiness(String reason) {
        throw new BrokenCurrentCompositeBusinessException(reason);
    }

    @Override
    public void broken(String reason) {
        flowExecutorConfig.flowExecutorRootConfig.brokenReason = reason;
        throw new BrokenException(reason);
    }

    @Override
    public QuickFlowExecutor startFlow(String name) {
        FlowExecutorConfig flowExecutorConfig = new FlowExecutorConfig();
        flowExecutorConfig.name = name;
        flowExecutorConfig.flowContext = QuickFlowUtil.getFlowContextInvocationHandler(flowExecutorConfig);
        Map<String,Object> currentCompositeFlowDataMap = new HashMap<String,Object>();
        if(null!=this.flowExecutorConfig.currentCompositeFlowDataMap){
            currentCompositeFlowDataMap.putAll(this.flowExecutorConfig.currentCompositeFlowDataMap);
        }
        flowExecutorConfig.currentCompositeFlowDataMap = currentCompositeFlowDataMap;
        flowExecutorConfig.parentFlowExecutorConfig = this.flowExecutorConfig;
        flowExecutorConfig.flowExecutorRootConfig = this.flowExecutorConfig.flowExecutorRootConfig;
        return QuickFlowUtil.getQuickFlowExecutorInvocationHandler(flowExecutorConfig);
    }

    @Override
    public QuickFlowExecutor startFlow(BusinessFlow businessFlow) {
        return startFlow(businessFlow.name()).next(businessFlow);
    }

    @Override
    public QuickFlowExecutor startFlow(CompositeBusinessFlow compositeBusinessFlow) {
        return QuickFlowUtil.getCompositeQuickFlowExecutor(compositeBusinessFlow, flowExecutorConfig);
    }

    @Override
    public FlowContext executeFunctionFlowList(String... functionFlowNames) {
        for(String functionFlowName:functionFlowNames){
            FunctionFlow functionFlow = (FunctionFlow) flowExecutorConfig.flowContext.checkData(functionFlowName);
            try {
                functionFlow.executeFunction(flowExecutorConfig.flowContext);
            } catch (BrokenException e){
                throw e;
            } catch (Exception e){
                throw new QuickFlowRuntimeException(e);
            }
        }
        return flowExecutorConfig.flowContext;
    }

    @Override
    public FlowContext executeFlowList(BusinessFlow... businessFlowList) {
        Boolean printTrace = flowExecutorConfig.printTrace;
        try {
            flowExecutorConfig.printTrace = false;
            for(BusinessFlow businessFlow:businessFlowList){
                try {
                    businessFlow.executeBusinessFlow(flowExecutorConfig.flowContext);
                }catch (BrokenCurrentFlowException e){
                    flowExecutorConfig.printFlowTraceWithIndex("|[x]|"+ businessFlow.name() + "|当前流程中断|中断原因:" + e.getReason() + flowExecutorConfig.getRemarkBuilder().toString());
                }
            }
        }catch (BrokenCurrentCompositeBusinessException | BrokenException e){
            if(null==flowExecutorConfig.ignoreBroken||!flowExecutorConfig.ignoreBroken){
                throw e;
            }
        }catch (Exception e){
            throw new QuickFlowRuntimeException(e);
        }finally {
            flowExecutorConfig.printTrace = printTrace;
        }
        return flowExecutorConfig.flowContext;
    }

    @Override
    public FlowContext executeCompositeFlowList(CompositeBusinessFlow... compositeBusinessFlowList) {
        BusinessFlow[] businessFlowArray = new BusinessFlow[compositeBusinessFlowList.length];
        for(int i=0;i<compositeBusinessFlowList.length;i++) {
            businessFlowArray[i] = QuickFlowUtil.getBusinessFlow(compositeBusinessFlowList[i]);
        }
        executeFlowList(businessFlowArray);
        return flowExecutorConfig.flowContext;
    }
}
